import java.util.Arrays;

public class Game {
    static final int LEN = 1076;
    static final int PLAYER_LEN = 10;
    public Field field;
    public Ball ball;
    public int player_count;
    public Player[] player;

    public Game(){}

    public Game(byte[] data){
        int dataUsedLen = 0;
        field = new Field(data,dataUsedLen);
        dataUsedLen += Field.LEN;
        ball = new Ball(data,dataUsedLen);
        dataUsedLen += Ball.LEN;
        player_count = Utils.readInt(data, dataUsedLen);
        dataUsedLen += Utils.INT_LEN;
        player = new Player[PLAYER_LEN];
        for (int i = 0; i < player_count; i++) {
            player[i] = new Player(data,dataUsedLen);
            dataUsedLen += Player.LEN;
        }
    }

    @Override
    public String toString() {
        return "Game{" +
                "\nfield=" + field +
                ", \nball=" + ball +
                ", \nplayer_count=" + player_count +
                ", \nplayer=" + Arrays.toString(player) +
                "\n}";
    }

    public Player getSelf(){
        for (int i = 0; i < player_count; i++) {
            if(player[i].id==Client.playerID){
                return player[i];
            }
        }
        return null;
    }
}

class Field {
    static final int LEN = 8;
    public float x;
    public float y;

    public Field(byte[] data) {
        this(data,0);
    }
    public Field(byte[] data, int offset) {
        x = Utils.readFloat(data, offset);
        y = Utils.readFloat(data, offset+4);
    }

    @Override
    public String toString() {
        return "Field{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

class Ball {
    static final int LEN = 24;
    public int pid;
    public float radius;
    public float x;
    public float y;

    public Ball(byte[] data) {
        this(data,0);
    }

    public Ball(byte[] data, int offset) {
        pid = Utils.readInt(data, offset);
        radius = Utils.readFloat(data, offset+4);
        x = Utils.readFloat(data, offset+8);
        y = Utils.readFloat(data, offset+12);
    }

    @Override
    public String toString() {
        return "Ball{" +
                "pid=" + pid +
                ", radius=" + radius +
                ", x=" + x +
                ", y=" + y +
                '}';
    }
}

class Player {
    static final int LEN = 104;
    public int id;
    public String name;
    public int side;
    public float radius;
    public float x;
    public float y;
    public float angle;

    public Player(byte[] data) {
        this(data,0);
    }

    public Player(byte[] data, int offset) {
        id = Utils.readInt(data, offset);
        name = Utils.readString(data, offset+4, 64);
        side = Utils.readInt(data, offset+68);
        radius = Utils.readFloat(data, offset+72);
        x = Utils.readFloat(data, offset+76);
        y = Utils.readFloat(data, offset+80);
        angle = Utils.readFloat(data, offset+84);
    }

    @Override
    public String toString() {
        return "\nPlayer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", side=" + side +
                ", radius=" + radius +
                ", x=" + x +
                ", y=" + y +
                ", angle=" + angle +
                '}';
    }
}

class Request {
    static final int LEN = 68;

    static final int GET_STATUS = 0;
    static final int UPDATE_SELF = 1;
    static final int JOIN_GAME = 2;
    static final int QUIT_GAME = 3;

    static final int TURN_LEFT = 0x01;
    static final int TURN_RIGHT = 0x02;
    static final int MOVE_LEFT = 0x04;
    static final int MOVE_RIGHT = 0x08;
    static final int MOVE_FORWARD = 0x10;
    static final int MOVE_BACKWARD = 0x20;
    static final int SHOOT = 0x40;
    static final int SPEED_UP = 0x80;

    int flag;
    String name;
    int id;
    int move;

    public Request(int flag) {
        this.flag = flag;
    }

    byte[] toBytes() {
        byte[] data = new byte[LEN];

        Utils.writeInt(flag, data, 0);
        switch (flag) {
            case UPDATE_SELF:
                Utils.writeInt(id, data, 4);
                Utils.writeInt(move, data, 8);
                break;
            case JOIN_GAME:
                Utils.writeString(name, data, 4, 64);
                break;
            case QUIT_GAME:
                Utils.writeInt(id, data, 4);
                break;
        }
        return data;
    }
}